#include "socket.hpp"
#include "Log.hxx"
#include <string>
#include <vector>
#include <memory>
#include <array>
#include <sys/poll.h>
#include <algorithm>
#include <sys/time.h>
#include <poll.h>
using namespace Net_TcpSocket;

class PollServer{

    
    public:
    PollServer(int16_t port)
    :_port(port)
    ,_listenSock(new TcpSocket)
    ,_pollFds()
    {
        _listenSock ->BuildListenSocket(_port,default_backlog); 
    }
    void InitSelect()
    {
        int opt = 1;
        setsockopt(_listenSock->GetSockfd(),SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
        struct pollfd pfd;
        pfd.fd = _listenSock->GetSockfd();
        pfd.events = POLLIN;
        pfd.revents = 0;
        _pollFds.push_back(pfd);
    }
    private:
    //应该还有处理一些异常事件，比如链接断开等等
    void HandleReadEvent()
    {
        for(const auto &pfd:_pollFds)
        {
            if(pfd.fd<0)
            {
                myService::lg(myService::Log::Error,"文件描述符为负数，出现错误，可能是输入poll管理时未正确初始化\n");
                continue;
            }
            int fd = pfd.fd;
            short revents = pfd.revents;
            if(revents & POLLIN)
            {
                //判断文件描述符类型处理事件
                if(fd == _listenSock->GetSockfd())
                {
                    myService::lg(myService::Log::Info,"Get a new Tcp Link\n");
                    struct sockaddr ip;
                    socklen_t len = sizeof(ip);
                    //先暂时不关心ip和port，理论上一般时要存起来的，这里主要演示poll
                    int sockfd = accept(_listenSock->GetSockfd(),&ip,&len);
                    if(sockfd<0)
                    {
                        myService::lg(myService::Log::Error,"accept error,errno %d,errstr %s",errno,strerror(errno));
                    }
                    struct pollfd newpollfd;
                    newpollfd.events = POLLIN;
                    newpollfd.fd = sockfd;
                    newpollfd.revents = 0;
                    _pollFds.push_back(newpollfd);
                }
                else
                {
                    //普通的读取事件
                    char buf[2048] = {0};
                    int n = read(fd,buf,sizeof(buf));
                    if(n<=0)
                    {
                        //读取失败，可能是链接断开，也可能是读取到0，这里不关心
                        myService::lg(myService::Log::Info,"read error,errno %d,errstr %s",errno,strerror(errno));
                        close(fd);
                        _pollFds.erase(std::remove_if(_pollFds.begin(),_pollFds.end(),[fd](const auto &pfd)->bool{
                            return pfd.fd == fd;
                        }),_pollFds.end());
                    }
                    else
                    {
                        //读取成功，这里可以进行业务处理
                        myService::lg(myService::Log::Info,"read %d bytes data\n",n);
                        //打印客户端输入的内容
                        myService::lg(myService::Log::Info,"client input:%s\n",buf);
                    }
                }
            }

        }
    }
    public:
    void WorkLoop()
    {
        _IsRunning = true;
        while(_IsRunning)
        {
            PrintDebug();
            int timeout = 1000 *1;
            int n = poll(_pollFds.data(),_pollFds.size(),timeout);
            switch(n)
            {
                case 0:
                myService::lg(myService::Log::Info,"select timeout");
                break;
                case -1:
                myService::lg(myService::Log::Error,"select error,errno %d,errstr %s",errno,strerror(errno));
                break;
                default:
                //新的读时间就绪
                myService::lg(myService::Log::Info,"select Read Event   ");
                HandleReadEvent();
                break;
            }
        }
        _IsRunning = false;
    }
    void PrintDebug()
    {
        //打印当前poll管理的文件描述符
        myService::lg(myService::Log::Info,"pollfd size %d",_pollFds.size());
        for(auto &pfd:_pollFds)
        {
           std::cout<<
           "fd:"<<pfd.fd<<"  ";
        }
        std::cout<<std::endl;
    }
    void Stop()
    {
        _IsRunning = false;
    }
    ~PollServer()
    {

    }
    private:
    std::shared_ptr<Socket> _listenSock;
    int16_t _port;
    bool _IsRunning;
    std::vector<struct pollfd> _pollFds;
};